package com.igroupes.ovineherd.model;

import com.igroupes.ovineherd.dto.request.GetRequestAttribute;
import com.igroupes.ovineherd.dto.request.GetRequestWhereNode;
import com.igroupes.ovineherd.entity.DataModelAttributeEntity;
import com.igroupes.ovineherd.service.impl.ModelApiServiceImpl;
import com.igroupes.ovineherd.util.Requires;
import com.igroupes.ovineherd.util.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.apache.commons.collections.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.stream.Collectors;

@Data
public class RelGetRequestAttribute {
    private Paging paging;
    private List<Ordering> ordering;
    private RelGetRequestWhereNode conditions;


    @Data
    @AllArgsConstructor
    public static class Paging {
        private int page;
        private int size;
    }

    @Data
    @AllArgsConstructor
    public static class Ordering {
        private String fieldName;
        private boolean isStr;
        private boolean asc;
    }

    private RelGetRequestWhereNode setRelWhere(GetRequestWhereNode requestNode, Map<String, DataModelAttributeEntity> fieldMap, BiFunction<Map<String, DataModelAttributeEntity>, String, ModelApiServiceImpl.RelFieldInfo> function) {
        if (requestNode == null) {
            return null;
        }
        RelGetRequestWhereNode node = new RelGetRequestWhereNode();
        node.setConjunction(Requires.requireNonNull(RelGetRequestWhereNode.ConnRelation.valueOf(requestNode.getConjunction().toUpperCase())));
        List<RelGetRequestWhereNode.FieldWithValue> fieldWithValues = requestNode.getChildren().stream().map(ele -> covert(ele, fieldMap, function)).collect(Collectors.toList());
        node.setChildren(fieldWithValues);
        return node;
    }

    private RelGetRequestWhereNode.FieldWithValue covert(GetRequestWhereNode.FieldWithValue src, Map<String, DataModelAttributeEntity> fieldMap, BiFunction<Map<String, DataModelAttributeEntity>, String, ModelApiServiceImpl.RelFieldInfo> function) {
        RelGetRequestWhereNode.FieldWithValue fieldWithValue = new RelGetRequestWhereNode.FieldWithValue();
        fieldWithValue.setRight(src.getRight());

        if (src.getLeft() != null && StringUtils.isNotBlank(src.getOp())) {
            ModelApiServiceImpl.RelFieldInfo relFieldInfo = function.apply(fieldMap, src.getLeft().getField());
            fieldWithValue.setFieldName(relFieldInfo.getFieldName());
            fieldWithValue.setStr(relFieldInfo.isStr());
        }
        if (StringUtils.isNotBlank(src.getConjunction())) {
            fieldWithValue.setConjunction(RelGetRequestWhereNode.ConnRelation.valueOf(src.getConjunction().toUpperCase()));
        }
        if (StringUtils.isNotBlank(src.getOp())) {
            fieldWithValue.setOp(RelGetRequestWhereNode.OpType.valueOf(src.getOp().toUpperCase()));
        }
        if (CollectionUtils.isNotEmpty(src.getChildren())) {
            fieldWithValue.setChildren(src.getChildren().stream().map(ele -> covert(ele, fieldMap, function)).collect(Collectors.toList()));
        }
        return fieldWithValue;
    }


    public void byGetRequestAttribute(Map<String, DataModelAttributeEntity> fieldMap,
                                      BiFunction<Map<String, DataModelAttributeEntity>, String, ModelApiServiceImpl.RelFieldInfo> function
            , GetRequestAttribute getRequestAttribute) {
        if (getRequestAttribute == null) {
            return;
        }
        this.setConditions(setRelWhere(getRequestAttribute.getConditions(), fieldMap, function));
        if (getRequestAttribute.getPaging() != null) {
            GetRequestAttribute.Paging paging = getRequestAttribute.getPaging();
            this.setPaging(new Paging(paging.getPage(), paging.getSize()));
        }
        if (getRequestAttribute.getOrdering() != null) {
            List<GetRequestAttribute.Ordering> ordering = getRequestAttribute.getOrdering();
            this.setOrdering(ordering.stream().map(o -> {
                ModelApiServiceImpl.RelFieldInfo relFieldInfo = function.apply(fieldMap, o.getFieldId());
                return new Ordering(relFieldInfo.getFieldName(), relFieldInfo.isStr(), o.isAsc());
            }).collect(Collectors.toList()));
        }

    }


}
